﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;
using SHomeWorkshop.LunarConcept.Adorners;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Enums;
using SHomeWorkshop.LunarConcept.ModifingManager;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Widgets
{
    /// <summary>
    /// 创建时间：2012年1月16日前
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：直线部件。
    /// </summary>
    public class StraitLineWidget : ArrowLineWidget, ICanSameSize, Interfaces.ILinkableLine, Interfaces.ITextRotate
    {
        #region 构造方法=====================================================================================================

        static StraitLineWidget()
        {
            contextMenu = (ContextMenu)Globals.MainWindow.MainGrid.FindResource("CMDicStraitLineWidget");
        }

        /// <summary>
        /// [构造方法]
        /// </summary>
        public StraitLineWidget(PageEditor masterEditor)
            : base(masterEditor)
        {
            this.ContextMenu = contextMenu;

            widgetType = Enums.WidgetTypes.StraitLine;
            widgetClassLocalName = Widget.GetWidgetClassLocalName(this.GetType().Name);

            mainLine.Stroke = mainLine.Fill = this.widgetForeColor;
            mainLine.StrokeThickness = widgetLineWidth;

            mainLine.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(mainLine_PreviewMouseLeftButtonDown);
            mainLine.PreviewMouseRightButtonUp += new MouseButtonEventHandler(mainLine_PreviewMouseRightButtonUp);

            this.mainCanvas.Children.Add(mainLine);

            Canvas.SetZIndex(mainLine, 0);

            #region 两个箭头。
            //startArrowPath.Cursor = Cursors.Arrow;
            startArrowPath.Fill = startArrowPath.Stroke = this.widgetForeColor;
            startArrowPath.StrokeThickness = widgetLineWidth;
            PathGeometry startArrowPg = new PathGeometry();
            startArrowPath.Data = startArrowPg;

            startArrowPathFigure.IsClosed = true;
            startArrowPathFigure.IsFilled = true;
            startArrowPathFigure.Segments.Add(startArrowPolyLineSegment);

            startArrowPg.Figures.Add(startArrowPathFigure);

            //endArrowPath.Cursor = Cursors.Arrow;
            endArrowPath.Fill = endArrowPath.Stroke = this.widgetForeColor;
            endArrowPath.StrokeThickness = widgetLineWidth;
            PathGeometry endArrowPg = new PathGeometry();
            endArrowPath.Data = endArrowPg;

            endArrowPathFigure.IsClosed = true;
            endArrowPathFigure.IsFilled = true;
            endArrowPathFigure.Segments.Add(endArrowPolyLineSegment);

            endArrowPg.Figures.Add(endArrowPathFigure);

            mainCanvas.Children.Add(startArrowPath);
            mainCanvas.Children.Add(endArrowPath);

            Canvas.SetZIndex(startArrowPath, 1);
            Canvas.SetZIndex(endArrowPath, 1);
            #endregion

            startCtrl = new LineCtrlAdorner(this.mainLine, this, Brushes.Red) { Visibility = Visibility.Hidden };
            endCtrl = new LineCtrlAdorner(this.mainLine, this, Brushes.Blue) { Visibility = Visibility.Hidden };
            startPresentateAdorner = new WidgetPresentateAdorner(this.mainLine, this, Brushes.Red) { Visibility = Visibility.Hidden };
            startPresentateAdorner.PreviewMouseLeftButtonDown += PresentateAdorner_PreviewMouseLeftButtonDown;
            endPresentateAdorner = new WidgetPresentateAdorner(this.mainLine, this, Brushes.Blue) { Visibility = Visibility.Hidden };
            endPresentateAdorner.PreviewMouseLeftButtonDown += PresentateAdorner_PreviewMouseLeftButtonDown;

            startCtrl.ToolTip = endCtrl.ToolTip = "双击鼠标左键设置备注文本";

            this.commentAdorner = new CommentAdorner(this.mainLine, this) { Visibility = System.Windows.Visibility.Collapsed };//默认不显示。
            this.commentAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(commentAdorner_MouseLeftButtonUp);

            this.hyperLinkAdorner = new HyperLinkAdorner(this.mainLine, this) { Visibility = Visibility.Collapsed };
            this.hyperLinkAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(hyperLinkAdorner_MouseLeftButtonUp);

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.mainCanvas);
            if (adornerLayer == null)
            {
                MessageBox.Show("　　未找到Widget的装饰层！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            else
            {
                adornerLayer.Add(this.startCtrl);
                adornerLayer.Add(this.endCtrl);
                adornerLayer.Add(this.startPresentateAdorner);
                adornerLayer.Add(this.endPresentateAdorner);
                adornerLayer.Add(this.commentAdorner);//这个要在各具体部件类中添加。
                adornerLayer.Add(this.hyperLinkAdorner);//这个要在各具体部件类中添加。
            }

            startCtrl.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(startCtrl_MouseLeftButtonDown);
            endCtrl.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(endCtrl_MouseLeftButtonDown);
            startArrowPath.MouseLeftButtonDown += new MouseButtonEventHandler(startArrowPath_MouseLeftButtonDown);
            endArrowPath.MouseLeftButtonDown += new MouseButtonEventHandler(endArrowPath_MouseLeftButtonDown);

            //最后添加文本面板。//已移动到基类中。
            //this.mainCanvas.Children.Add(this.mainTextPanel);
            //Canvas.SetZIndex(this.mainTextPanel, 2);

            this.ControlHandlerDoubleClicked += StraitLineWidget_ControlHandlerDoubleClicked;
        }

        private bool isPresentating = false;
        /// <summary>
        /// 是否处于演示状态。
        /// </summary>
        public bool IsPresentating
        {
            get { return isPresentating; }
            set
            {
                isPresentating = value;
                RefreshWidgetLineColor();
            }
        }

        private void PresentateAdorner_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            IsPresentating = !IsPresentating;
            this.IsSelected = false;
            e.Handled = true;
        }

        private void StraitLineWidget_ControlHandlerDoubleClicked(object sender, MouseButtonEventArgs e)
        {
            LunarMessage.Warning(Commands.SetCommentTextCommand.Execute());
        }

        #endregion


        #region 字段与属性===================================================================================================

        private double textRotateAngle = 0;
        /// <summary>
        /// [读写]文本旋转角度。取值范围：[-180,180]。
        /// </summary>
        [Tools.LunarProperty("TextRotateAngle", PropertyDateType.Double)]
        public double TextRotateAngle
        {
            get { return textRotateAngle; }
            set
            {
                if (value > 180)
                {
                    textRotateAngle = 180;
                }
                else if (value < -180)
                {
                    textRotateAngle = -180;
                }
                else
                {
                    textRotateAngle = value;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.TextRotateAngleTag, textRotateAngle.ToString());
                }

                this.RefreshTextRotateAngle();
            }
        }

        /// <summary>
        /// [只读]返回以直线为对角线的矩形的左上角。
        /// </summary>
        public override Point TopLeft
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(startPoint.X, endPoint.X);
                maxRight = Math.Max(startPoint.X, endPoint.X);

                minTop = Math.Min(startPoint.Y, endPoint.Y);
                maxBottom = Math.Min(startPoint.Y, endPoint.Y);

                return new Point(minLeft, minTop);
            }
        }

        /// <summary>
        /// [只读]返回以直线为对角线的矩形的右下角。
        /// </summary>
        public override Point BottomRight
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(startPoint.X, endPoint.X);
                maxRight = Math.Max(startPoint.X, endPoint.X);

                minTop = Math.Min(startPoint.Y, endPoint.Y);
                maxBottom = Math.Max(startPoint.Y, endPoint.Y);

                return new Point(maxRight, maxBottom);
            }
        }

        #region 两侧箭头

        public override void RefreshArrows()
        {
            base.RefreshArrows();

            switch (arrows)
            {
                case ArrowType.None:
                    {
                        mainLine.X1 = startPoint.X; mainLine.Y1 = startPoint.Y;
                        mainLine.X2 = endPoint.X; mainLine.Y2 = endPoint.Y;
                        return;
                    }
                case ArrowType.Start:
                    {
                        startArrowPathFigure.StartPoint = startPoint;
                        ArrowPoints apStart = new ArrowPoints(
                            startArrowPathFigure.StartPoint, endPoint, widgetLineWidth * 2);

                        startArrowPolyLineSegment.Points = new PointCollection(){
                            apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                        };
                        mainLine.X1 = apStart.ArrowRealTopPoint.X; mainLine.Y1 = apStart.ArrowRealTopPoint.Y;

                        mainLine.X2 = endPoint.X; mainLine.Y2 = endPoint.Y;
                        return;
                    }
                case ArrowType.End:
                    {
                        endArrowPathFigure.StartPoint = endPoint;
                        ArrowPoints apEnd = new ArrowPoints(
                            endPoint, startPoint, widgetLineWidth * 2);

                        endArrowPolyLineSegment.Points = new PointCollection(){
                            apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                        };
                        mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;

                        mainLine.X1 = startPoint.X; mainLine.Y1 = startPoint.Y;
                        return;
                    }
                default://All
                    {
                        startArrowPathFigure.StartPoint = startPoint;
                        ArrowPoints apStart = new ArrowPoints(
                            startArrowPathFigure.StartPoint, endPoint, widgetLineWidth * 2);

                        startArrowPolyLineSegment.Points = new PointCollection(){
                            apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                        };
                        mainLine.X1 = apStart.ArrowRealTopPoint.X; mainLine.Y1 = apStart.ArrowRealTopPoint.Y;

                        endArrowPathFigure.StartPoint = endPoint;
                        ArrowPoints apEnd = new ArrowPoints(
                            endPoint, startPoint, widgetLineWidth * 2);

                        endArrowPolyLineSegment.Points = new PointCollection(){
                            apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                        };
                        mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                        return;
                    }
            }
        }

        /// <summary>
        /// 刷新箭头状态。
        /// </summary>
        /// <param name="drawLine">若为真，按已设置的startPoint/startCPpoint/endCPPoint/endPoint画线及箭头。</param>
        private void RefreshArrows(bool drawLine)
        {
            base.RefreshArrows();

            if (drawLine) DrawLine();
        }

        #endregion

        /// <summary>
        /// 本类通用上下文菜单。
        /// </summary>
        private static ContextMenu contextMenu;

        private ControlDraggingType draggingType = ControlDraggingType.None;
        /// <summary>
        /// [只读]正在拖动哪个控制点。
        /// </summary>
        public ControlDraggingType DraggingType
        {
            get { return draggingType; }
        }

        private LineCtrlAdorner endCtrl;
        /// <summary>
        /// [只读]终点控制点。
        /// </summary>
        public LineCtrlAdorner EndCtrl
        {
            get { return endCtrl; }
        }

        private string endMasterId = string.Empty;
        /// <summary>
        /// [读写]尾端点挂接到的部件的Id。
        /// </summary>
        [Tools.LunarProperty("EndMasterId", PropertyDateType.String)]
        public string EndMasterId
        {
            get { return endMasterId; }
            set
            {
                endMasterId = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndMasterIdTag, value);
                }
            }
        }

        private Point endPoint = new Point();
        /// <summary>
        /// [读写]线的终点坐标。
        /// </summary>
        [Tools.LunarProperty("EndPoint", PropertyDateType.Point)]
        public Point EndPoint
        {
            get { return endPoint; }
            set
            {
                endPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndPointTag, endPoint.ToString());
                }

                RefreshLocation();
            }
        }

        private LinkToPoint endLinkTo = LinkToPoint.Center;
        /// <summary>
        /// 作连接线时才有意义。
        /// [读写]线的尾端点连接到目标部件的哪个连接点。
        /// </summary>
        [Tools.LunarProperty("EndLinkTo", PropertyDateType.LinkToPoint)]
        public LinkToPoint EndLinkTo
        {
            get { return endLinkTo; }
            set
            {
                endLinkTo = value;

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndLinkToTag, endLinkTo.ToString());
                }

                DrawLine();
            }
        }

        /// <summary>
        /// [只读]是否被挂接到两个ContentWidget。
        /// </summary>
        public bool IsLinked
        {
            get
            {
                if (startMasterId == string.Empty && endMasterId == string.Empty)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        /// <summary>
        /// 连接线永不被设置为锁定。
        /// </summary>
        [Tools.LunarProperty("IsLocked", PropertyDateType.Bool)]
        public override bool IsLocked
        {
            get
            {
                if (IsLinked) return false;

                return base.IsLocked;
            }
            set
            {
                if (IsLinked) return;//连接线不被设置为锁定。

                base.IsLocked = value;
            }
        }

        public override bool IsSelected
        {
            get { return this.isSelected; }
            set
            {
                base.IsSelected = value;

                this.RefreshIsSelected();
            }
        }

        private Line mainLine = new Line() { Cursor = Cursors.Hand };

        public Line MainLine { get { return this.mainLine; } }

        private string startMasterId = string.Empty;
        /// <summary>
        /// [读写]首端点挂接的部件的Id。
        /// </summary>
        [Tools.LunarProperty("StartMasterId", PropertyDateType.String)]
        public string StartMasterId
        {
            get { return startMasterId; }
            set
            {
                startMasterId = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartMasterIdTag, value);
                }
            }
        }

        private Point startPoint = new Point(0, 0);
        /// <summary>
        /// [读写]线的起点坐标。
        /// </summary>
        [Tools.LunarProperty("StartPoint", PropertyDateType.Point)]
        public Point StartPoint
        {
            get { return startPoint; }
            set
            {
                startPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartPointTag, startPoint.ToString());
                }

                RefreshLocation();
            }
        }

        private LinkToPoint startLinkTo = LinkToPoint.Center;
        /// <summary>
        /// 作连接线时才有意义。
        /// [读写]线的首端点连接到目标部件的哪个连接点。
        /// </summary>
        [Tools.LunarProperty("StartLinkTo", PropertyDateType.LinkToPoint)]
        public LinkToPoint StartLinkTo
        {
            get { return startLinkTo; }
            set
            {
                startLinkTo = value;

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartLinkToTag, startLinkTo.ToString());
                }

                DrawLine();
            }
        }

        private LineCtrlAdorner startCtrl;
        /// <summary>
        /// [只读]起点控制点。
        /// </summary>
        public LineCtrlAdorner StartCtrl
        {
            get { return startCtrl; }
        }

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        private WidgetPresentateAdorner startPresentateAdorner;

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        public WidgetPresentateAdorner StartPresentateAdorner { get { return startPresentateAdorner; } }

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        private WidgetPresentateAdorner endPresentateAdorner;

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        public WidgetPresentateAdorner EndPresentateAdorner { get { return endPresentateAdorner; } }

        #endregion


        #region 方法=========================================================================================================

        public override void Build()
        {
            base.Build();

            if (this.xmlData == null) return;

            XmlAttribute attrStartMasterId = this.xmlData.GetAttribute(XmlTags.StartMasterIdTag);
            if (attrStartMasterId != null)
            {
                this.startMasterId = attrStartMasterId.Value;
            }

            XmlAttribute attrEndMasterId = this.xmlData.GetAttribute(XmlTags.EndMasterIdTag);
            if (attrEndMasterId != null)
            {
                this.endMasterId = attrEndMasterId.Value;
            }

            XmlAttribute attrStartPoint = this.xmlData.GetAttribute(XmlTags.StartPointTag);
            if (attrStartPoint != null)
            {
                this.startPoint = FormatPoint(Point.Parse(attrStartPoint.Value));
            }

            XmlAttribute attrStartLinkTo = this.xmlData.GetAttribute(XmlTags.StartLinkToTag);
            if (attrStartLinkTo != null)
            {
                this.startLinkTo = (LinkToPoint)Enum.Parse(typeof(LinkToPoint), attrStartLinkTo.Value);
            }

            XmlAttribute attrEndPoint = this.xmlData.GetAttribute(XmlTags.EndPointTag);
            if (attrEndPoint != null)
            {
                this.endPoint = FormatPoint(Point.Parse(attrEndPoint.Value));
            }

            XmlAttribute attrEndLinkTo = this.xmlData.GetAttribute(XmlTags.EndLinkToTag);
            if (attrEndLinkTo != null)
            {
                this.endLinkTo = (LinkToPoint)Enum.Parse(typeof(LinkToPoint), attrEndLinkTo.Value);
            }

            //包含RefreshArrows()调用。
            this.RefreshLocation();

            //此类是下列Style properties的“最终实现类”。因此调用，
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();

        }

        protected override void BuildStyleProperties()
        {
            base.BuildStyleProperties();

            //此类没有任何与Style相关的Xml特性需要读取
        }

        public override void BuildWidgetStylePropertiesAndRefresh()
        {
            base.BuildWidgetStylePropertiesAndRefresh();

            //此类是下面这几个属性的“最终实现类”。这些属性的值都已在基类确定。因此调用,
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();

            //已在ArrowLineWidget类中调用。
            //this.RefreshWidgetBackColor();
            //this.RefreshArrows();

            //无意义
            //this.RefreshWidgetPadding();

            //这几个在Widget类中已经调用。
            //this.RefreshWidgetForeColor();
            //this.RefreshIsShadowVisible();
            //this.RefreshWidgetOpacity();
        }

        /// <summary>
        /// 根据“IsLinked”的结果分别重绘线条。
        /// </summary>
        public void DrawLine()
        {
            if (masterEditor == null) return;
            if (IsLinked)
            {
                Widget startWidget = masterEditor.GetWidget(this.StartMasterId);
                Widget endWidget = masterEditor.GetWidget(this.EndMasterId);
                if (startWidget == null || endWidget == null)
                {
                    DrawLine(this.startPoint, this.endPoint);
                    return;
                }

                Rect startRect = startWidget.OuterRect;
                Rect endRect = endWidget.OuterRect;
                DrawLine(startRect, endRect);
            }
            else
            {
                DrawLine(this.startPoint, this.endPoint);
            }
        }

        /// <summary>
        /// “IsLinked”为false时，表示此线未连接到ICanLinkedWidget部件。
        /// </summary>
        /// <param name="startPoint">首端点。</param>
        /// <param name="endPoint">尾端点。</param>
        private void DrawLine(Point startPoint, Point endPoint)
        {
            #region 旧版，不支持多箭头形态
            //if (arrows == ArrowType.None)
            //{
            //    mainLine.X1 = startPoint.X; mainLine.Y1 = startPoint.Y;
            //    mainLine.X2 = endPoint.X; mainLine.Y2 = endPoint.Y;
            //}
            //else
            //{
            //    if (arrows == ArrowType.All || arrows == ArrowType.Start)
            //    {
            //        startArrowPathFigure.StartPoint = startPoint;
            //        Tools.ArrowPoints apStart = new Tools.ArrowPoints(
            //            startArrowPathFigure.StartPoint, endPoint, widgetLineWidth * 2);

            //        startArrowPolyLineSegment.Points = new PointCollection(){
            //            apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
            //        };

            //        mainLine.X1 = apStart.ArrowRealTopPoint.X; mainLine.Y1 = apStart.ArrowRealTopPoint.Y;
            //    }
            //    else
            //    {
            //        mainLine.X1 = startPoint.X; mainLine.Y1 = startPoint.Y;
            //    }

            //    if (arrows == ArrowType.All || arrows == ArrowType.End)
            //    {
            //        endArrowPathFigure.StartPoint = endPoint;
            //        Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
            //            endArrowPathFigure.StartPoint, startPoint, widgetLineWidth * 2);

            //        endArrowPolyLineSegment.Points = new PointCollection(){
            //            apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
            //        };

            //        mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
            //    }
            //    else
            //    {
            //        mainLine.X2 = endPoint.X; mainLine.Y2 = endPoint.Y;
            //    }
            //}
            #endregion

            //startArrowPathFigure.StartPoint = startPoint;
            Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                startPoint, endPoint, Globals.MainWindow.EditorManager.DefaultFontSize);

            endArrowPathFigure.StartPoint = endPoint;
            Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                endPoint, startPoint, Globals.MainWindow.EditorManager.DefaultFontSize);
            startArrowPath.Fill = endArrowPath.Fill = WidgetBackColor;

            switch (arrows)
            {
                case ArrowType.Start:
                    startArrowPath.Fill = widgetLineColor;
                    endArrowPath.Fill = widgetLineColor;

                    startArrowPathFigure.StartPoint = startPoint;
                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                    };

                    mainLine.X1 = apStart.ArrowRealTopPoint.X; mainLine.Y1 = apStart.ArrowRealTopPoint.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    endArrowPathFigure.StartPoint = endPoint;
                    mainLine.X2 = apEnd.ArrowTopPoint.X; mainLine.Y2 = apEnd.ArrowTopPoint.Y;
                    break;
                case ArrowType.End:
                    startArrowPath.Fill = widgetLineColor;
                    endArrowPath.Fill = widgetLineColor;

                    startArrowPathFigure.StartPoint = startPoint;
                    mainLine.X1 = apStart.ArrowTopPoint.X; mainLine.Y1 = apStart.ArrowTopPoint.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    endArrowPathFigure.StartPoint = endPoint;
                    endArrowPolyLineSegment.Points = new PointCollection(){
                        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                    break;
                case ArrowType.All:
                    startArrowPath.Fill = widgetLineColor;
                    endArrowPath.Fill = widgetLineColor;

                    startArrowPathFigure.StartPoint = startPoint;
                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                    };

                    mainLine.X1 = apStart.ArrowRealTopPoint.X; mainLine.Y1 = apStart.ArrowRealTopPoint.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    endArrowPathFigure.StartPoint = endPoint;
                    endArrowPolyLineSegment.Points = new PointCollection(){
                        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                    break;
                case ArrowType.None:
                    startArrowPath.Fill = widgetLineColor;
                    endArrowPath.Fill = widgetLineColor;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    mainLine.X1 = startPoint.X; mainLine.Y1 = startPoint.Y;
                    mainLine.X2 = endPoint.X; mainLine.Y2 = endPoint.Y;

                    endArrowPathFigure.StartPoint = endPoint;
                    break;
                case ArrowType.EmptyStart:
                    startArrowPath.Fill = Brushes.Transparent; ;
                    endArrowPath.Fill = widgetBackColor;

                    mainLine.X1 = apStart.ArrowCenter.X; mainLine.Y1 = apStart.ArrowCenter.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    startArrowPathFigure.StartPoint = startPoint;
                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                    break;
                case ArrowType.RhombStart:
                    startArrowPath.Fill = WidgetLineColor;
                    endArrowPath.Fill = WidgetLineColor;
                    mainLine.X1 = apStart.ArrowBottom.X; mainLine.Y1 = apStart.ArrowBottom.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    startArrowPathFigure.StartPoint = startPoint;
                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowLeftPoint,apStart.ArrowBottom,apStart.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                    break;
                case ArrowType.EmptyRhombStart:
                    startArrowPath.Fill = Brushes.Transparent;
                    endArrowPath.Fill = widgetBackColor;

                    mainLine.X1 = apStart.ArrowBottom.X; mainLine.Y1 = apStart.ArrowBottom.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    startArrowPathFigure.StartPoint = startPoint;
                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowLeftPoint,apStart.ArrowBottom,apStart.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowRealTopPoint.X; mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                    break;
                case ArrowType.OpenArrowEnd:
                    startArrowPath.Fill = widgetLineColor;
                    endArrowPath.Fill = Brushes.Transparent;

                    startArrowPathFigure.StartPoint = startPoint;
                    endArrowPath.StrokeThickness = widgetLineWidth;

                    mainLine.X1 = apStart.ArrowRealTopPoint.X; mainLine.Y1 = apStart.ArrowRealTopPoint.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = false;

                    endArrowPathFigure.StartPoint = apEnd.ArrowLeftPoint;
                    endArrowPolyLineSegment.Points = new PointCollection(){
                        endPoint,apEnd.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowTopPoint.X; mainLine.Y2 = apEnd.ArrowTopPoint.Y;
                    break;
                case ArrowType.Arrow:
                    startArrowPath.Fill = WidgetLineColor;
                    endArrowPath.Fill = WidgetLineColor;

                    mainLine.X1 = apStart.ArrowBottom.X; mainLine.Y1 = apStart.ArrowBottom.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    startArrowPathFigure.StartPoint = apStart.ArrowRealTopPoint;
                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowRightTop,apStart.ArrowRightPoint,apStart.ArrowBottom,apStart.ArrowLeftPoint,apStart.ArrowLeftTop,
                    };

                    endArrowPathFigure.StartPoint = endPoint;
                    endArrowPolyLineSegment.Points = new PointCollection(){
                        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowCenter.X; mainLine.Y2 = apEnd.ArrowCenter.Y;
                    break;
                case ArrowType.EmptyArrow:
                    startArrowPath.Fill = Brushes.Transparent;
                    endArrowPath.Fill = Brushes.Transparent;

                    mainLine.X1 = apStart.ArrowBottom.X; mainLine.Y1 = apStart.ArrowBottom.Y;

                    startArrowPathFigure.IsClosed = true;
                    endArrowPathFigure.IsClosed = true;

                    startArrowPathFigure.StartPoint = apStart.ArrowRealTopPoint;
                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowRightTop,apStart.ArrowRightPoint,apStart.ArrowBottom,apStart.ArrowLeftPoint,apStart.ArrowLeftTop,
                    };

                    endArrowPathFigure.StartPoint = endPoint;
                    endArrowPolyLineSegment.Points = new PointCollection(){
                        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                    };

                    mainLine.X2 = apEnd.ArrowCenter.X; mainLine.Y2 = apEnd.ArrowCenter.Y;

                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// ★此方法不会调用DrawLine(Point,Point,Point,Point)方法来进行绘制。
        /// 
        /// “IsLinked”属性为true时，曲线被连接到两个ICanLinkedWidget部件。
        /// 此时，曲线的位置和形状由这两个部件的外框和曲线的两个控制点决定。
        /// 曲线的首端点、尾端点将自动计算，计算的规则是：“首控制点到首矩形的中心点与矩形的交战为首端点”。
        /// </summary>
        /// <param name="startRect">首连接部件外框。</param>
        /// <param name="endRect">尾连接部件外框。</param>
        private void DrawLine(Rect startRect, Rect endRect)
        {
            if (startRect.IntersectsWith(endRect))
            {
                startCtrl.Visibility =
                    endCtrl.Visibility =
                    mainLine.Visibility = Visibility.Hidden;
                return;
            }

            mainLine.Visibility = Visibility.Visible;
            this.RefreshArrows(false);
            if (isSelected)
            {
                startCtrl.Visibility =
                endCtrl.Visibility = Visibility.Visible;
            }

            //边缘留点空白区。
            startRect.X -= 4; startRect.Y -= 4; startRect.Width += 8; startRect.Height += 8;
            endRect.X -= 4; endRect.Y -= 4; endRect.Width += 8; endRect.Height += 8;

            if (this.startLinkTo == LinkToPoint.Center && this.endLinkTo == LinkToPoint.Center)
            {
                //首尾端点均指向中心
                DrawCenterToCenterLinkedLine(ref startRect, ref endRect);
            }
            else
            {
                if (this.startLinkTo == LinkToPoint.Center)
                {
                    //先求EndPoint，尾端点必定不是指向中心的
                    Point? endPoint = GetLinkedPoint(endRect, this.endLinkTo);
                    if (endPoint != null && endPoint.HasValue)
                    {
                        #region 首端点指中心，尾端点必定是指向八个边框点之一
                        PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(startRect, endPoint.Value);

                        // 旧版-Start
                        //startArrowPathFigure.StartPoint = aptStart.Top;
                        //if (startArrowPath.Visibility == Visibility.Visible)
                        //{
                        //    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                        //        aptStart.Top, endPoint.Value, widgetLineWidth * 2);

                        //    startArrowPolyLineSegment.Points = new PointCollection(){
                        //        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                        //    };

                        //    mainLine.X1 = apStart.ArrowRealTopPoint.X;
                        //    mainLine.Y1 = apStart.ArrowRealTopPoint.Y;
                        //}
                        //else
                        //{
                        //    mainLine.X1 = aptStart.Top.X;
                        //    mainLine.Y1 = aptStart.Top.Y;
                        //} 

                        //endArrowPathFigure.StartPoint = endPoint.Value;
                        //if (endArrowPath.Visibility == Visibility.Visible)
                        //{
                        //    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                        //    endPoint.Value, aptStart.Top, widgetLineWidth * 2);
                        //    endArrowPolyLineSegment.Points = new PointCollection(){
                        //        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                        //    };

                        //    mainLine.X2 = apEnd.ArrowRealTopPoint.X;
                        //    mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                        //}
                        //else
                        //{
                        //    mainLine.X2 = endPoint.Value.X;
                        //    mainLine.Y2 = endPoint.Value.Y;
                        //}
                        // 旧版-End

                        this.startCtrl.CenterPoint = aptStart.Top;
                        this.endCtrl.CenterPoint = endPoint.Value;

                        DrawLine(aptStart.Top, endPoint.Value);
                        #endregion
                    }
                    else
                    {
                        #region 首端点指中心，尾端点指向边框
                        var startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
                        var endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

                        Point newEnd;
                        switch (Globals.GetLocationArea(endRect, startCenter))
                        {
                            case LocationArea.Left:
                                newEnd = new Point(endRect.X, startCenter.Y);
                                break;
                            case LocationArea.LeftTop:
                                newEnd = endRect.TopLeft;
                                break;
                            case LocationArea.Top:
                                newEnd = new Point(startCenter.X, endRect.Y);
                                break;
                            case LocationArea.RightTop:
                                newEnd = endRect.TopRight;
                                break;
                            case LocationArea.Right:
                                newEnd = new Point(endRect.X + endRect.Width, startCenter.Y);
                                break;
                            case LocationArea.RightBottom:
                                newEnd = endRect.BottomRight;
                                break;
                            case LocationArea.Bottom:
                                newEnd = new Point(startCenter.X, endRect.Bottom);
                                break;
                            case LocationArea.LeftBottom:
                                newEnd = endRect.BottomLeft;
                                break;
                            //case LocationArea.Center:
                            default:
                                newEnd = endCenter;
                                break;
                        }

                        PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(startRect, newEnd);
                        // 旧版-Start
                        //startArrowPathFigure.StartPoint = aptStart.Top;

                        //if (startArrowPath.Visibility == Visibility.Visible)
                        //{
                        //    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                        //        aptStart.Top, newEnd, widgetLineWidth * 2);

                        //    startArrowPolyLineSegment.Points = new PointCollection(){
                        //        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                        //    };

                        //    mainLine.X1 = apStart.ArrowRealTopPoint.X;
                        //    mainLine.Y1 = apStart.ArrowRealTopPoint.Y;
                        //}
                        //else
                        //{
                        //    mainLine.X1 = aptStart.Top.X;
                        //    mainLine.Y1 = aptStart.Top.Y;
                        //}

                        //endArrowPathFigure.StartPoint = newEnd;
                        //if (endArrowPath.Visibility == Visibility.Visible)
                        //{
                        //    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                        //    newEnd, aptStart.Top, widgetLineWidth * 2);
                        //    endArrowPolyLineSegment.Points = new PointCollection(){
                        //        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                        //    };

                        //    mainLine.X2 = apEnd.ArrowRealTopPoint.X;
                        //    mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                        //}
                        //else
                        //{
                        //    mainLine.X2 = newEnd.X;
                        //    mainLine.Y2 = newEnd.Y;
                        //} 
                        // 旧版-End

                        this.startCtrl.CenterPoint = aptStart.Top;
                        this.endCtrl.CenterPoint = newEnd;

                        DrawLine(aptStart.Top, newEnd);
                        #endregion
                    }
                }
                else if (this.endLinkTo == LinkToPoint.Center)
                {
                    #region 先求StartPoint，首端点必定是八个边框点之一
                    Point? startPoint = GetLinkedPoint(startRect, this.startLinkTo);
                    if (startPoint != null && startPoint.HasValue)
                    {
                        PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(endRect, startPoint.Value);
                        // 旧版-Start
                        //endArrowPathFigure.StartPoint = aptEnd.Top;
                        //if (endArrowPath.Visibility == Visibility.Visible)
                        //{
                        //    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                        //    aptEnd.Top, startPoint.Value, widgetLineWidth * 2);
                        //    endArrowPolyLineSegment.Points = new PointCollection(){
                        //        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                        //    };

                        //    mainLine.X2 = apEnd.ArrowRealTopPoint.X;
                        //    mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                        //}
                        //else
                        //{
                        //    mainLine.X2 = aptEnd.Top.X;
                        //    mainLine.Y2 = aptEnd.Top.Y;
                        //}

                        //this.startCtrl.CenterPoint = startPoint.Value;
                        //this.endCtrl.CenterPoint = aptEnd.Top;

                        //startArrowPathFigure.StartPoint = startPoint.Value;

                        //if (startArrowPath.Visibility == Visibility.Visible)
                        //{
                        //    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                        //        startPoint.Value, aptEnd.Top, widgetLineWidth * 2);

                        //    startArrowPolyLineSegment.Points = new PointCollection(){
                        //        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                        //    };

                        //    mainLine.X1 = apStart.ArrowRealTopPoint.X;
                        //    mainLine.Y1 = apStart.ArrowRealTopPoint.Y;
                        //}
                        //else
                        //{
                        //    mainLine.X1 = startPoint.Value.X;
                        //    mainLine.Y1 = startPoint.Value.Y;
                        //}
                        // 旧版-End
                        DrawLine(startPoint.Value, endPoint);
                    }
                    #endregion
                }
                else
                {
                    //两端都不指向中心
                    Point? startPoint = GetLinkedPoint(startRect, this.startLinkTo);
                    Point? endPoint = GetLinkedPoint(endRect, this.endLinkTo);
                    if (startPoint != null && startPoint.HasValue)
                    {
                        if (endPoint != null && endPoint.HasValue)
                        {
                            #region 首端点为八个边框点之一，尾端点也是八个边框点之一
                            //startArrowPathFigure.StartPoint = startPoint.Value;

                            //if (startArrowPath.Visibility == Visibility.Visible)
                            //{
                            //    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                            //        startPoint.Value, endPoint.Value, widgetLineWidth * 2);

                            //    startArrowPolyLineSegment.Points = new PointCollection(){
                            //    apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                            //};

                            //    mainLine.X1 = apStart.ArrowRealTopPoint.X;
                            //    mainLine.Y1 = apStart.ArrowRealTopPoint.Y;
                            //}
                            //else
                            //{
                            //    mainLine.X1 = startPoint.Value.X;
                            //    mainLine.Y1 = startPoint.Value.Y;
                            //}

                            //endArrowPathFigure.StartPoint = endPoint.Value;
                            //if (endArrowPath.Visibility == Visibility.Visible)
                            //{
                            //    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                            //    endPoint.Value, startPoint.Value, widgetLineWidth * 2);
                            //    endArrowPolyLineSegment.Points = new PointCollection(){
                            //    apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                            //};

                            //    mainLine.X2 = apEnd.ArrowRealTopPoint.X;
                            //    mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                            //}
                            //else
                            //{
                            //    mainLine.X2 = endPoint.Value.X;
                            //    mainLine.Y2 = endPoint.Value.Y;
                            //}

                            this.startCtrl.CenterPoint = startPoint.Value;
                            this.endCtrl.CenterPoint = endPoint.Value;
                            DrawLine(startPoint.Value, endPoint.Value);
                            #endregion
                        }
                        else
                        {
                            #region 首端点为八个边框点之一，尾端点指向边框
                            var startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
                            var endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

                            Point newEnd;
                            switch (Globals.GetLocationArea(endRect, startPoint.Value))
                            {
                                case LocationArea.Left:
                                    newEnd = new Point(endRect.X, startPoint.Value.Y);
                                    break;
                                case LocationArea.LeftTop:
                                    newEnd = endRect.TopLeft;
                                    break;
                                case LocationArea.Top:
                                    newEnd = new Point(startPoint.Value.X, endRect.Y);
                                    break;
                                case LocationArea.RightTop:
                                    newEnd = endRect.TopRight;
                                    break;
                                case LocationArea.Right:
                                    newEnd = new Point(endRect.X + endRect.Width, startPoint.Value.Y);
                                    break;
                                case LocationArea.RightBottom:
                                    newEnd = endRect.BottomRight;
                                    break;
                                case LocationArea.Bottom:
                                    newEnd = new Point(startPoint.Value.X, endRect.Bottom);
                                    break;
                                case LocationArea.LeftBottom:
                                    newEnd = endRect.BottomLeft;
                                    break;
                                //case LocationArea.Center:
                                default:
                                    newEnd = endCenter;
                                    break;
                            }

                            Point newStartPoint;
                            var pt = GetLinkedPoint(startRect, StartLinkTo);
                            if (pt != null && pt.HasValue) newStartPoint = pt.Value;
                            else newStartPoint = startCenter;

                            PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(startRect, newStartPoint);
                            //startArrowPathFigure.StartPoint = aptStart.Top;

                            //if (startArrowPath.Visibility == Visibility.Visible)
                            //{
                            //    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                            //        aptStart.Top, newEnd, widgetLineWidth * 2);

                            //    startArrowPolyLineSegment.Points = new PointCollection(){
                            //    apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                            //};

                            //    mainLine.X1 = apStart.ArrowRealTopPoint.X;
                            //    mainLine.Y1 = apStart.ArrowRealTopPoint.Y;
                            //}
                            //else
                            //{
                            //    mainLine.X1 = aptStart.Top.X;
                            //    mainLine.Y1 = aptStart.Top.Y;
                            //}

                            //endArrowPathFigure.StartPoint = newEnd;
                            //if (endArrowPath.Visibility == Visibility.Visible)
                            //{
                            //    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                            //    newEnd, aptStart.Top, widgetLineWidth * 2);
                            //    endArrowPolyLineSegment.Points = new PointCollection(){
                            //    apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                            //};

                            //    mainLine.X2 = apEnd.ArrowRealTopPoint.X;
                            //    mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
                            //}
                            //else
                            //{
                            //    mainLine.X2 = newEnd.X;
                            //    mainLine.Y2 = newEnd.Y;
                            //}

                            this.startCtrl.CenterPoint = aptStart.Top;
                            this.endCtrl.CenterPoint = newEnd;
                            DrawLine(aptStart.Top, newEnd);
                            #endregion
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 当linkToPoint的值为Center或Border时，返回null。
        /// </summary>
        internal Point? GetLinkedPoint(Rect linkedRect, LinkToPoint linkToPoint)
        {
            switch (linkToPoint)
            {
                case LinkToPoint.TopLeft: return linkedRect.TopLeft;
                case LinkToPoint.Top: return new Point(linkedRect.Left + linkedRect.Width / 2, linkedRect.Top);
                case LinkToPoint.TopRight: return linkedRect.TopRight;
                case LinkToPoint.Left: return new Point(linkedRect.Left, linkedRect.Top + linkedRect.Height / 2);
                case LinkToPoint.Right: return new Point(linkedRect.Right, linkedRect.Top + linkedRect.Height / 2);
                case LinkToPoint.BottomLeft: return linkedRect.BottomLeft;
                case LinkToPoint.Bottom: return new Point(linkedRect.Left + linkedRect.Width / 2, linkedRect.Bottom);
                case LinkToPoint.BottomRight: return linkedRect.BottomRight;
                default: return null;
            }
        }

        private void DrawCenterToCenterLinkedLine(ref Rect startRect, ref Rect endRect)
        {
            Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
            Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

            PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(startRect, endCenter);
            #region 旧版
            //startArrowPathFigure.StartPoint = aptStart.Top;

            //if (startArrowPath.Visibility == Visibility.Visible)
            //{
            //    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
            //        aptStart.Top, endCenter, widgetLineWidth * 2);

            //    startArrowPolyLineSegment.Points = new PointCollection(){
            //        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
            //    };

            //    mainLine.X1 = apStart.ArrowRealTopPoint.X;
            //    mainLine.Y1 = apStart.ArrowRealTopPoint.Y;
            //}
            //else
            //{
            //    mainLine.X1 = aptStart.Top.X;
            //    mainLine.Y1 = aptStart.Top.Y;
            //} 
            #endregion

            PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(endRect, startCenter);
            #region 旧版
            //endArrowPathFigure.StartPoint = aptEnd.Top;
            //if (endArrowPath.Visibility == Visibility.Visible)
            //{
            //    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
            //    aptEnd.Top, startCenter, widgetLineWidth * 2);
            //    endArrowPolyLineSegment.Points = new PointCollection(){
            //        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
            //    };

            //    mainLine.X2 = apEnd.ArrowRealTopPoint.X;
            //    mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;
            //}
            //else
            //{
            //    mainLine.X2 = aptEnd.Top.X;
            //    mainLine.Y2 = aptEnd.Top.Y;
            //} 
            #endregion

            this.startCtrl.CenterPoint = aptStart.Top;
            this.endCtrl.CenterPoint = aptEnd.Top;

            DrawLine(aptStart.Top, aptEnd.Top);
        }

        /// <summary>
        /// 重定文本位置。
        /// </summary>
        /// <param name="startPoint">首端点。</param>
        /// <param name="endPoint">尾端点。</param>
        private void LocateTextPanel(Point startPoint, Point endPoint)
        {
            Point center = new Point(startPoint.X + (endPoint.X - startPoint.X) / 2,
                            startPoint.Y + (endPoint.Y - startPoint.Y) / 2);

            Point textStart = new Point(center.X - this.mainBorder.ActualWidth / 2 - this.mainBorder.Margin.Left,
                center.Y - this.mainBorder.ActualHeight / 2 - this.mainBorder.Margin.Top);

            Canvas.SetLeft(this.mainBorder, textStart.X);
            Canvas.SetTop(this.mainBorder, textStart.Y);
        }

        private void LocateTextPanel(Rect startRect, Rect endRect)
        {
            //边缘留点空白区。
            startRect.X -= 4; startRect.Y -= 4; startRect.Width += 8; startRect.Height += 8;
            endRect.X -= 4; endRect.Y -= 4; endRect.Width += 8; endRect.Height += 8;

            Point startCenter = new Point(startRect.Left + startRect.Width / 2,
                startRect.Top + startRect.Height / 2);
            Point endCenter = new Point(endRect.Left + endRect.Width / 2,
                endRect.Top + endRect.Height / 2);

            Point startPoint, endPoint;
            if (this.startLinkTo == LinkToPoint.Center && this.endLinkTo == LinkToPoint.Center)
            {
                Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endCenter);
                Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startCenter);

                startPoint = aptStart.Top;
                endPoint = aptEnd.Top;
            }
            else
            {
                if (this.startLinkTo == LinkToPoint.Center)
                {
                    Point? newEndPoint = this.GetLinkedPoint(endRect, this.endLinkTo);
                    if (newEndPoint != null && newEndPoint.HasValue)
                    {
                        endPoint = newEndPoint.Value;
                        Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endPoint);
                        startPoint = aptStart.Top;
                    }
                    else
                    {
                        Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endCenter);
                        Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startCenter);

                        startPoint = aptStart.Top;
                        endPoint = aptEnd.Top;
                    }
                }
                else if (this.endLinkTo == LinkToPoint.Center)
                {
                    Point? newStartPoint = this.GetLinkedPoint(startRect, this.startLinkTo);
                    if (newStartPoint != null && newStartPoint.HasValue)
                    {
                        startPoint = newStartPoint.Value;
                        Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startPoint);
                        endPoint = aptEnd.Top;
                    }
                    else
                    {
                        Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endCenter);
                        Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startCenter);

                        startPoint = aptStart.Top;
                        endPoint = aptEnd.Top;
                    }
                }
                else
                {
                    Point? newStartPoint = this.GetLinkedPoint(startRect, this.startLinkTo);
                    Point? newEndPoint = this.GetLinkedPoint(endRect, this.endLinkTo);

                    if (newStartPoint != null && newStartPoint.HasValue && newEndPoint != null && newEndPoint.HasValue)
                    {
                        startPoint = newStartPoint.Value;
                        endPoint = newEndPoint.Value;
                    }
                    else
                    {
                        Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endCenter);
                        Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startCenter);

                        startPoint = aptStart.Top;
                        endPoint = aptEnd.Top;
                    }
                }
            }

            LocateTextPanel(startPoint, endPoint);//都不是成员字段。
        }

        public override void DropWidget(ModifingItem<Action, ModifingInfo> mi, Point mousePoint)
        {
            if (mi == null) return;

            Point globalLocation = masterEditor.MouseInfo.LeftButtonPreviewPoint;

            Point newStartPoint = new Point(
                startPoint.X - globalLocation.X + mousePoint.X, startPoint.Y - globalLocation.Y + mousePoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name,
                XmlTags.StartPointTag, startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(
                endPoint.X - globalLocation.X + mousePoint.X, endPoint.Y - globalLocation.Y + mousePoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.ModifingInfo.NewMainSelectedWidgetID = this.id;
            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);

            this.RefreshCommentText();
            this.RefreshHyperLinkText();

            RefreshPresentateAdorners();
        }

        public override void DropWidgetControler(Point newMovingPoint, ModifingItem<Action, ModifingInfo> mi)
        {
            if (mi == null || mi.ModifingInfo == null) return;

            ModifingInfo info = mi.ModifingInfo;

            bool isShift = false;

            KeyStates ksLShift = Keyboard.GetKeyStates(Key.LeftShift);
            KeyStates ksRShift = Keyboard.GetKeyStates(Key.RightShift);

            if ((ksLShift & KeyStates.Down) > 0 || (ksRShift & KeyStates.Down) > 0)
            {
                isShift = true;
            }

            switch (draggingType)
            {
                case ControlDraggingType.Start:
                    {
                        if (isShift)
                        {
                            double horizontalDistance = Math.Abs(newMovingPoint.X - endPoint.X);
                            double verticalDistance = Math.Abs(newMovingPoint.Y - endPoint.Y);

                            if (verticalDistance > horizontalDistance)
                            {
                                if (verticalDistance > horizontalDistance * 2)
                                {
                                    newMovingPoint.X = endPoint.X;
                                }
                                else
                                {
                                    int qua = Getquadrant(newMovingPoint, endPoint);
                                    switch (qua)
                                    {
                                        case 1:
                                            {
                                                newMovingPoint.Y = endPoint.Y - (newMovingPoint.X - endPoint.X); break;
                                            }
                                        case 2:
                                            {
                                                newMovingPoint.Y = endPoint.Y + (newMovingPoint.X - endPoint.X); break;
                                            }
                                        case 3:
                                            {
                                                newMovingPoint.Y = endPoint.Y - (newMovingPoint.X - endPoint.X); break;
                                            }
                                        case 4:
                                            {
                                                newMovingPoint.Y = endPoint.Y + (newMovingPoint.X - endPoint.X); break;
                                            }
                                    }
                                }
                            }
                            else
                            {
                                if (verticalDistance * 2 < horizontalDistance)
                                {
                                    newMovingPoint.Y = endPoint.Y;
                                }
                                else
                                {
                                    int qua = Getquadrant(newMovingPoint, endPoint);
                                    switch (qua)
                                    {
                                        case 1:
                                            {
                                                newMovingPoint.Y = endPoint.Y - (newMovingPoint.X - endPoint.X); break;
                                            }
                                        case 2:
                                            {
                                                newMovingPoint.Y = endPoint.Y + (newMovingPoint.X - endPoint.X); break;
                                            }
                                        case 3:
                                            {
                                                newMovingPoint.Y = endPoint.Y - (newMovingPoint.X - endPoint.X); break;
                                            }
                                        case 4:
                                            {
                                                newMovingPoint.Y = endPoint.Y + (newMovingPoint.X - endPoint.X); break;
                                            }
                                    }
                                }
                            }
                        }

                        Point oldStartPoint = StartPoint;

                        if (Math.Abs(newMovingPoint.X - oldStartPoint.X) <= 4 &&
                            Math.Abs(newMovingPoint.Y - oldStartPoint.Y) <= 4)
                        {
                            mainLine.X1 = oldStartPoint.X; mainLine.Y1 = oldStartPoint.Y;
                            break;//移动距离过短，应视为点击。
                        }

                        info.ModifingDescription = "拖动直线首端点";

                        if (masterEditor != null && masterEditor.MasterManager != null)
                        {
                            masterEditor.MasterManager.GetSelectedPageEditorStatus(info);
                            masterEditor.MasterManager.GetSelectedWidgetStatus_Old(info);
                            masterEditor.MasterManager.GetSelectedWidgetStatus_New(info);
                        }

                        Action actDraggingLineHeader = new Action(masterEditor.Id, this.id, this.GetType().Name,
                            XmlTags.StartPointTag, oldStartPoint.ToString(), newMovingPoint.ToString());

                        StartPoint = newMovingPoint;

                        RefreshControlers();

                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);
                        break;
                    }
                case ControlDraggingType.End:
                    {
                        info.ModifingDescription = "拖动直线尾端点";

                        if (masterEditor != null && masterEditor.MasterManager != null)
                        {
                            masterEditor.MasterManager.GetSelectedPageEditorStatus(info);
                            masterEditor.MasterManager.GetSelectedWidgetStatus_Old(info);
                            masterEditor.MasterManager.GetSelectedWidgetStatus_New(info);
                        }

                        Point oldEndPoint = endPoint;

                        if (Math.Abs(newMovingPoint.X - oldEndPoint.X) <= 4 &&
                            Math.Abs(newMovingPoint.Y - oldEndPoint.Y) <= 4)
                        {
                            mainLine.X2 = oldEndPoint.X; mainLine.Y2 = oldEndPoint.Y;
                            break;//移动距离过短，应视为点击。
                        }

                        if (isShift)
                        {
                            double vD = Math.Abs(newMovingPoint.Y - startPoint.Y);
                            double hD = Math.Abs(newMovingPoint.X - startPoint.X);

                            if (vD > hD)
                            {
                                if (vD > hD * 2)
                                {
                                    newMovingPoint.X = startPoint.X;
                                }
                                else
                                {
                                    int qua = Getquadrant(newMovingPoint, startPoint);
                                    switch (qua)
                                    {
                                        case 1:
                                            {
                                                newMovingPoint.Y = startPoint.Y - (newMovingPoint.X - startPoint.X); break;
                                            }
                                        case 2:
                                            {
                                                newMovingPoint.Y = startPoint.Y + (newMovingPoint.X - startPoint.X); break;
                                            }
                                        case 3:
                                            {
                                                newMovingPoint.Y = startPoint.Y - (newMovingPoint.X - startPoint.X); break;
                                            }
                                        case 4:
                                            {
                                                newMovingPoint.Y = startPoint.Y + (newMovingPoint.X - startPoint.X); break;
                                            }
                                    }
                                }
                            }
                            else
                            {
                                if (vD * 2 < hD)
                                {
                                    newMovingPoint.Y = startPoint.Y;
                                }
                                else
                                {
                                    int qua = Getquadrant(newMovingPoint, startPoint);
                                    switch (qua)
                                    {
                                        case 1:
                                            {
                                                newMovingPoint.Y = startPoint.Y - (newMovingPoint.X - startPoint.X); break;
                                            }
                                        case 2:
                                            {
                                                newMovingPoint.Y = startPoint.Y + (newMovingPoint.X - startPoint.X); break;
                                            }
                                        case 3:
                                            {
                                                newMovingPoint.Y = startPoint.Y - (newMovingPoint.X - startPoint.X); break;
                                            }
                                        case 4:
                                            {
                                                newMovingPoint.Y = startPoint.Y + (newMovingPoint.X - startPoint.X); break;
                                            }
                                    }
                                }
                            }
                        }

                        Action actDraggingLineHeader = new Action(masterEditor.Id, this.id, this.GetType().Name,
                            XmlTags.EndPointTag, oldEndPoint.ToString(), newMovingPoint.ToString());

                        EndPoint = newMovingPoint;

                        RefreshControlers();

                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);
                        break;
                    }
            }

            this.RefreshCommentText();
            this.RefreshHyperLinkText();

            RefreshPresentateAdorners();
        }

        void endArrowPath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            endCtrl_MouseLeftButtonDown(sender, e);
        }

        void endCtrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            this.SelectOnlySelf();

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = endPoint;
            draggingType = ControlDraggingType.End;
            masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveLineWidgetControler;

            endCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        private Point FormatStartMovingPoint(Point newInsideMovingPoint, Point endPoint)
        {
            double horizontalDistance = newInsideMovingPoint.X - endPoint.X;
            double verticalDistance = newInsideMovingPoint.Y - endPoint.Y;

            double absHD = Math.Abs(horizontalDistance);
            double absVD = Math.Abs(verticalDistance);

            if (absVD > absHD)
            {
                if (absVD > absHD * 2)
                {
                    newInsideMovingPoint = new Point(endPoint.X, newInsideMovingPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(newInsideMovingPoint, endPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 2:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 3:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 4:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                    endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                    }
                }
            }
            else
            {
                if (absVD * 2 < absHD)
                {
                    newInsideMovingPoint = new Point(newInsideMovingPoint.X, endPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(newInsideMovingPoint, endPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 2:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 3:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 4:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                    endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                    }
                }
            }

            return newInsideMovingPoint;
        }

        /// <summary>
        /// 以basePoint为基础坐标，画出四象限。
        /// 取出pt在哪个象限中。
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="basePoint"></param>
        /// <returns></returns>
        private int Getquadrant(Point pt, Point basePoint)
        {
            if (pt.X > basePoint.X)
            {
                if (pt.Y > basePoint.Y)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                if (pt.Y > basePoint.Y)
                {
                    return 3;
                }
                else
                {
                    return 2;
                }
            }
        }

        public override string GetRelativeOuterXml(Point baseCopyTopLeft)
        {
            if (this.xmlData == null) return string.Empty;

            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseCopyTopLeft.X,
                oldStartPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.StartPointTag, newStartPoint.ToString());

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseCopyTopLeft.X,
                oldEndPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.EndPointTag, newEndPoint.ToString());

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(this.xmlData.OuterXml);

            this.xmlData.SetAttribute(XmlTags.StartPointTag, oldStartPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.EndPointTag, oldEndPoint.ToString());

            return sb.ToString();
        }

        /// <summary>
        /// 这个虚方法是用以查看本部件是否在选定框的内部。
        /// 线型部件，各有各的计算办法。
        /// </summary>
        public override bool IsInRect(Rect rect)
        {
            //return base.IsInRect(rect);//这个要屏蔽。
            bool isInRect = base.IsInRect(rect);
            if (isInRect)
            {
                return true;
            }
            else
            {
                //这个法子还不完善。线是否“穿过”矩形还得另想办法。
                return rect.Contains(startPoint) || rect.Contains(endPoint);
            }
        }

        void mainLine_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //双击编辑文本
            if (e.ClickCount == 2)
            {
                this.SelectOnlySelf();
                if (Globals.MainWindow.IsPresentatingByPath == false)
                {
                    this.Edit();
                }
                return;
            }

            ModifingItem<Action, ModifingInfo> mi = null;
            ModifingInfo info = null;
            if (FormatSelf(ref mi, ref info))
            {
                if (masterEditor != null)
                {
                    masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                }
                return;//格式刷格式化，不更改选定状态。
            }

            KeyStates ksRightShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLeftShift = Keyboard.GetKeyStates(Key.LeftShift);

            bool isShift = false;

            if ((ksRightShift & KeyStates.Down) > 0 || (ksLeftShift & KeyStates.Down) > 0) { isShift = true; }

            bool isCtrl = false;
            KeyStates ksRightCtrl = Keyboard.GetKeyStates(Key.RightCtrl);
            KeyStates ksLeftCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);

            if ((ksRightCtrl & KeyStates.Down) > 0 || (ksLeftCtrl & KeyStates.Down) > 0) isCtrl = true;

            if (isShift && isCtrl == false)
            {
                //基本规则：
                //    ①如果未选定，选定，并作为活动部件。
                //    ②如果已选定，看是否是活动部件，如果已经是活动部件，整个取消选定状态；
                //                                      如果不是活动部件，设为活动部件。
                if (this.IsSelected == false)
                {
                    this.IsMainSelected = true;
                }
                else
                {
                    if (this.IsMainSelected == false)
                    {
                        this.IsMainSelected = true;
                    }
                    else
                    {
                        this.IsSelected = false;
                    }
                }
            }
            else
            {
                if (IsSelected == false)
                {
                    this.SelectOnlySelf();
                }
                //如果是选定的部件，那么可能是在拖动。
            }

            //准备拖动。
            if (masterEditor != null)
            {
                masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                Point pt = e.GetPosition(this.masterEditor);
                pt = new Point(pt.X - this.masterEditor.BorderThickness.Left, pt.Y - this.masterEditor.BorderThickness.Top);
                masterEditor.MouseInfo.LeftButtonPreviewPoint = pt;
            }
        }

        void mainLine_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            if (this.IsSelected == false)
            {
                //如果未选定，就作为活动，
                this.SelectOnlySelf();
            }
            else
            {
                //若已选定，不更改选定范围，只更改“活动部件”为此部件
                if (this.IsMainSelected == false) this.IsMainSelected = true;
            }

            if (this.ContextMenu != null)
            {
                this.ContextMenu.IsOpen = true;
            }
        }

        public override void MoveUp(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - units);
            Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - units);
            Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        public override void MoveDown(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y + units);
            Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y + units);
            Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        public override void MoveLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X - units, startPoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - units, endPoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        public override void MoveRight(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X + units, startPoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X + units, endPoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        /// <summary>
        /// 改变中心点横坐标。
        /// </summary>
        public override void MoveHorizontalCenterTo(ModifingItem<Action, ModifingInfo> mi, double center)
        {
            if (mi == null || double.IsNaN(center) || masterEditor == null) return;

            double offset = 0;
            double curCenter = TopLeft.X + (BottomRight.X - TopLeft.X) / 2;
            offset = curCenter - center;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 改变中心点纵坐标。
        /// </summary>
        public override void MoveVerticalCenterTo(ModifingItem<Action, ModifingInfo> mi, double center)
        {
            if (mi == null || double.IsNaN(center) || masterEditor == null) return;

            double offset = 0;
            double curCenter = TopLeft.Y + (BottomRight.Y - TopLeft.Y) / 2;
            offset = curCenter - center;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveDown不同，这里是指定向下移动到哪个位置（下边缘到哪个位置）。
        /// </summary>
        public override void MoveBottomSiderTo(ModifingItem<Action, ModifingInfo> mi, double bottom)
        {
            if (mi == null || double.IsNaN(bottom) || masterEditor == null) return;

            double offset = 0;
            double maxBottom = BottomRight.Y;
            offset = maxBottom - bottom;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveLeft不同，这里是指定向左移动到哪个位置（左边缘到哪个位置）。
        /// </summary>
        public override void MoveLeftSiderTo(ModifingItem<Action, ModifingInfo> mi, double left)
        {
            if (mi == null || double.IsNaN(left) || masterEditor == null) return;

            double offset = 0;
            double minLeft = TopLeft.X;
            offset = minLeft - left;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveRight不同，这里是指定向右移动到哪个位置（右边缘到哪个位置）。
        /// </summary>
        public override void MoveRightSiderTo(ModifingItem<Action, ModifingInfo> mi, double right)
        {
            if (mi == null || double.IsNaN(right) || masterEditor == null) return;

            double offset = 0;
            double maxRight = BottomRight.X;
            offset = maxRight - right;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveUp不同，这里是指定向上移动到哪个位置（上边缘到哪个位置）。
        /// </summary>
        public override void MoveTopSiderTo(ModifingItem<Action, ModifingInfo> mi, double top)
        {
            if (mi == null || double.IsNaN(top) || masterEditor == null) return;

            double offset = 0;
            double minTop = TopLeft.Y;
            offset = minTop - top;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        public override void MoveWhenDraggingControler(Point newOutSidePoint)
        {
            bool isShift = false;

            KeyStates ksLShift = Keyboard.GetKeyStates(Key.LeftShift);
            KeyStates ksRShift = Keyboard.GetKeyStates(Key.RightShift);

            if ((ksLShift & KeyStates.Down) > 0 || (ksRShift & KeyStates.Down) > 0)
            {
                isShift = true;
            }

            switch (draggingType)
            {
                case ControlDraggingType.Start:
                    {
                        Point newMovingPoint = newOutSidePoint;
                        if (isShift)
                        {
                            newMovingPoint = FormatStartMovingPoint(newMovingPoint, endPoint);
                        }

                        DrawLine(newMovingPoint, this.endPoint);
                        LocateTextPanel(newMovingPoint, this.endPoint);
                        break;
                    }
                case ControlDraggingType.End:
                    {
                        Point newMovingPoint = newOutSidePoint;

                        if (isShift)
                        {
                            newMovingPoint = FormatStartMovingPoint(newMovingPoint, startPoint);
                        }

                        DrawLine(this.startPoint, newMovingPoint);
                        LocateTextPanel(this.startPoint, newMovingPoint);
                        break;
                    }
            }

            this.commentAdorner.Visibility =
                this.hyperLinkAdorner.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// 移动挂接的主部件时，与此部件连接的线（就是本类的某个实例）需要自动相应地移动。
        /// </summary>
        /// <param name="tmpStartMasterRect">如果指定了此参数，则startRect应按此参数来移动。</param>
        /// <param name="tmpEndMasterRect">如果指定了此参数，则endRect应按此参数来移动。</param>
        public void MoveWhenDraggingMasterWidget(Rect? tmpStartMasterRect = null, Rect? tmpEndMasterRect = null)
        {
            ICanBeLinkedWidget startMaster = masterEditor.GetWidget(startMasterId) as ICanBeLinkedWidget;
            ICanBeLinkedWidget endMaster = masterEditor.GetWidget(endMasterId) as ICanBeLinkedWidget;
            if (startMaster == null || endMaster == null) return;

            Rect startRect = tmpStartMasterRect.HasValue ? tmpStartMasterRect.Value : startMaster.MovingRect;
            Rect endRect = tmpEndMasterRect.HasValue ? tmpEndMasterRect.Value : endMaster.MovingRect;

            if (startRect.IntersectsWith(endRect))
            {
                startArrowPath.Visibility = endArrowPath.Visibility =
                mainLine.Visibility = Visibility.Hidden;
            }
            else
            {
                switch (arrows)
                {
                    case ArrowType.All:
                        {
                            startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Visible; break;
                        }
                    case ArrowType.End:
                        {
                            startArrowPath.Visibility = Visibility.Hidden;
                            endArrowPath.Visibility = Visibility.Visible;
                            break;
                        }
                    case ArrowType.Start:
                        {
                            startArrowPath.Visibility = Visibility.Visible;
                            endArrowPath.Visibility = Visibility.Hidden;
                            break;
                        }
                    case ArrowType.None:
                        {
                            startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Hidden; break;
                        }
                }

                mainLine.Visibility = Visibility.Visible;
            }

            Point startCenter = new Point(startRect.Left + startRect.Width / 2,
                startRect.Top + startRect.Height / 2);
            Point endCenter = new Point(endRect.Left + endRect.Width / 2,
                endRect.Top + endRect.Height / 2);

            Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endCenter);
            Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startCenter);

            DrawLine(startRect, endRect);
            LocateTextPanel(startRect, endRect);

        }

        public override void MoveWhenDraggingWidget(Point mousePoint)
        {
            Point newMovingPoint = mousePoint;

            Point globalLocation = masterEditor.MouseInfo.LeftButtonPreviewPoint;

            Point tmpStartPoint = new Point(startPoint.X - globalLocation.X + newMovingPoint.X,
                startPoint.Y - globalLocation.Y + newMovingPoint.Y);
            Point tmpEndPoint = new Point(endPoint.X - globalLocation.X + newMovingPoint.X,
                endPoint.Y - globalLocation.Y + newMovingPoint.Y);

            startCtrl.CenterPoint = tmpStartPoint;
            endCtrl.CenterPoint = tmpEndPoint;

            DrawLine(tmpStartPoint, tmpEndPoint);
            LocateTextPanel(tmpStartPoint, tmpEndPoint);

            this.commentAdorner.Visibility =
                this.hyperLinkAdorner.Visibility = Visibility.Collapsed;

            //startArrowPathFigure.StartPoint = tmpStartPoint;
            //ArrowPoints apStart = new ArrowPoints(
            //    tmpStartPoint, tmpEndPoint, lineWidth * 2);
            //startArrowPolyLineSegment.Points = new PointCollection()
            //{
            //    apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
            //};
            //mainLine.X1 = apStart.ArrowRealTopPoint.X;
            //mainLine.Y1 = apStart.ArrowRealTopPoint.Y;

            //endArrowPathFigure.StartPoint = tmpEndPoint;
            //ArrowPoints apEnd = new ArrowPoints(
            //    tmpEndPoint, tmpStartPoint, lineWidth * 2);
            //endArrowPolyLineSegment.Points = new PointCollection()
            //{
            //    apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
            //};
            //mainLine.X2 = apEnd.ArrowRealTopPoint.X;
            //mainLine.Y2 = apEnd.ArrowRealTopPoint.Y;

            //startCtrl.CenterPoint = apStart.ArrowTopPoint;
            //endCtrl.CenterPoint = apEnd.ArrowTopPoint;

            //Point center = new Point(apStart.ArrowRealTopPoint.X +
            //                (apEnd.ArrowRealTopPoint.X - apStart.ArrowRealTopPoint.X) / 2,
            //                apStart.ArrowRealTopPoint.Y +
            //                (apEnd.ArrowRealTopPoint.Y - apStart.ArrowRealTopPoint.Y) / 2);

            //Point textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left,
            //    center.Y - this.mainTextPanel.ActualHeight / 2 - this.mainTextPanel.Margin.Top);

            //Canvas.SetLeft(this.mainTextPanel, textStart.X);
            //Canvas.SetTop(this.mainTextPanel, textStart.Y);
        }

        /// <summary>
        /// 刷新所有控制点。
        /// </summary>
        public override void RefreshControlers()
        {
            //显示控制点。
            if (this.isSelected)
            {
                //刷新控制点色彩
                if (masterEditor != null && masterEditor.MasterManager != null)
                {
                    if (startCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetStartControlerBrush)
                        startCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetStartControlerBrush;

                    if (endCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetEndControlerBrush)
                        endCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetEndControlerBrush;
                }

                startCtrl.Visibility = endCtrl.Visibility = Visibility.Visible;
                this.startCtrl.InvalidateVisual();
                this.endCtrl.InvalidateVisual();
            }
            else
            {
                startCtrl.Visibility = endCtrl.Visibility = Visibility.Hidden;
            }
        }

        /// <summary>
        /// 刷新线宽。
        /// </summary>
        public override void RefreshWidgetLineWidth()
        {
            //强制直线跳过宽度１（当作２看待）——因为会模糊，很难看。
            //mainLine.StrokeThickness = (widgetLineWidth < 2 ? 2 : widgetLineWidth);

            double newLineWidth = (widgetLineWidth < 1 ? 1 : widgetLineWidth);
            mainLine.StrokeThickness = newLineWidth;//还是支持宽度1的线为妙。

            if (widgetLineWidth == 1)
            {
                if ((int)this.mainLine.X1 == (int)this.mainLine.X2 || (int)this.mainLine.Y1 == (int)this.mainLine.Y2)
                {
                    RenderOptions.SetEdgeMode(mainLine, EdgeMode.Aliased);
                }
                else
                {
                    RenderOptions.SetEdgeMode(mainLine, EdgeMode.Unspecified);
                }
            }
            else
            {
                RenderOptions.SetEdgeMode(mainLine, EdgeMode.Unspecified);
            }

            startArrowPath.StrokeThickness = endArrowPath.StrokeThickness = newLineWidth;
        }

        public override void RefreshLocation()
        {
            base.RefreshLocation();

            RefreshStartPoint();
            RefreshEndPoint();

            RefreshControlers();
            RefreshArrows();   // 2022年5月3日以后不需要了。

            this.RefreshTextRotateAngle();
            // this.RefreshWidgetLineWidth();   //this.RefreshWidgetLineWidth()方法中会调用此方法。

            //if (IsLinked)
            //{
            //    if (Math.Abs(startPoint.X - endPoint.X) <= 2 && Math.Abs(startPoint.Y - endPoint.Y) <= 2)
            //    {
            //        startArrowPath.Visibility = endArrowPath.Visibility =
            //            mainLine.Visibility = Visibility.Hidden;
            //    }
            //    else
            //    {
            //        mainLine.Visibility = Visibility.Visible;
            //    }
            //}

            DrawLine();  // 这个要移到后面来，不然会出错。

            RefreshPresentateAdorners();
        }

        public void RefreshPresentateAdorners()
        {
            if (Globals.MainWindow.rtbtnAutoHideStraitLine.IsChecked == true && Globals.MainWindow.IsPresentatingByPath)
            {
                this.startPresentateAdorner.Visibility = this.endPresentateAdorner.Visibility = Visibility.Visible;
                this.startPresentateAdorner.InvalidateVisual();
                this.endPresentateAdorner.InvalidateVisual();
            }
            else
            {
                this.startPresentateAdorner.Visibility = this.endPresentateAdorner.Visibility = Visibility.Hidden;
            }
        }

        public override void RefreshLineDash()
        {
            switch (lineDash)
            {
                case LineDashType.DashType.Dash:
                    {
                        //this.startArrowPath.StrokeDashArray = LineDashType.dashCollection;
                        //this.endArrowPath.StrokeDashArray = LineDashType.dashCollection;
                        this.mainLine.StrokeDashArray = LineDashType.dashCollection; break;
                    }
                case LineDashType.DashType.DashDotDot:
                    {
                        //this.startArrowPath.StrokeDashArray = LineDashType.dashDotDotCollection;
                        //this.endArrowPath.StrokeDashArray = LineDashType.dashDotDotCollection;
                        this.mainLine.StrokeDashArray = LineDashType.dashDotDotCollection; break;
                    }
                case LineDashType.DashType.Dot:
                    {
                        //this.startArrowPath.StrokeDashArray = LineDashType.dotCollection;
                        //this.endArrowPath.StrokeDashArray = LineDashType.dotCollection;
                        this.mainLine.StrokeDashArray = LineDashType.dotCollection; break;
                    }
                case LineDashType.DashType.DashDot:
                    {
                        //this.startArrowPath.StrokeDashArray = LineDashType.solidCollection;
                        //this.endArrowPath.StrokeDashArray = LineDashType.solidCollection;
                        this.mainLine.StrokeDashArray = LineDashType.dashDotCollection; break;
                    }
                default:
                    {
                        //this.startArrowPath.StrokeDashArray = LineDashType.dashDotCollection;
                        //this.endArrowPath.StrokeDashArray = LineDashType.dashDotCollection;
                        this.mainLine.StrokeDashArray = LineDashType.solidCollection; break;
                    }
            }
        }

        public override void RefreshIsSelected()
        {
            base.RefreshIsSelected();

            if (startMasterId != string.Empty)
            {
                startCtrl.Form = LineCtrlAdorner.ControlerType.Rectangle;
            }
            else
            {
                startCtrl.Form = LineCtrlAdorner.ControlerType.Ellipse;
            }

            if (endMasterId != string.Empty)
            {
                endCtrl.Form = LineCtrlAdorner.ControlerType.Rectangle;
            }
            else
            {
                endCtrl.Form = LineCtrlAdorner.ControlerType.Ellipse;
            }
        }

        private void RefreshEndPoint()
        {
            endCtrl.CenterPoint = endPoint;
            mainLine.X2 = endPoint.X;
            mainLine.Y2 = endPoint.Y;

            Canvas.SetLeft(endCtrl, endPoint.X - endCtrl.Width / 2);
            Canvas.SetTop(endCtrl, endPoint.Y - endCtrl.Height / 2);
        }

        public override void RefreshIsShadowVisible()
        {
            base.RefreshIsShadowVisible();

            if (isShadowVisible)
            {
                this.mainLine.Effect = Widget.ShadowEffect;
            }
            else
            {
                this.mainLine.Effect = null;
            }
        }

        private void RefreshStartPoint()
        {
            startCtrl.CenterPoint = startPoint;
            mainLine.X1 = startPoint.X;
            mainLine.Y1 = startPoint.Y;

            Canvas.SetLeft(startCtrl, startPoint.X - startCtrl.Width / 2);
            Canvas.SetTop(startCtrl, startPoint.Y - startCtrl.Height / 2);
        }

        public override void RefreshPointWhenGroupIn(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseTopLeft.X,
                oldStartPoint.Y - baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseTopLeft.X,
                oldEndPoint.Y - baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public override void RefreshPointWhenGroupOut(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X + baseTopLeft.X,
                oldStartPoint.Y + baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X + baseTopLeft.X,
                oldEndPoint.Y + baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public override void RefreshTextPanelLocatin()
        {
            LocateTextPanel(this.startPoint, this.endPoint);
        }

        /// <summary>
        /// 刷新文本区旋转角度。
        /// </summary>
        public void RefreshTextRotateAngle()
        {
            if (this.mainBorder.RenderTransformOrigin != DefaultRenderCenter)
            {
                this.mainBorder.RenderTransformOrigin = DefaultRenderCenter;
            }

            if (this.textRotateAngle == 0)
            {
                this.mainBorder.RenderTransform = DefaultRotateTransform;
            }
            else
            {
                this.mainBorder.RenderTransform = new RotateTransform(textRotateAngle);
            }
        }

        public override void RefreshWidgetLineColor()
        {
            if (Globals.MainWindow.rtbtnAutoHideBazeirLine.IsChecked == true && Globals.MainWindow.IsPresentatingByPath)
            {
                if (IsPresentating)
                {
                    this.startArrowPath.Fill =
                        this.startArrowPath.Stroke =
                        this.endArrowPath.Fill =
                        this.endArrowPath.Stroke =
                         this.mainLine.Stroke = Brushes.Transparent;
                }
                else
                {
                    this.startArrowPath.Fill =
                        this.startArrowPath.Stroke =
                        this.endArrowPath.Fill =
                        this.endArrowPath.Stroke =
                        this.mainLine.Stroke = this.widgetLineColor;
                }
            }
            else
            {

                startArrowPath.Stroke = endArrowPath.Stroke =
                    startArrowPath.Fill = endArrowPath.Fill =
                        mainLine.Stroke = WidgetLineColor;
            }
        }

        public override void CollapseToTop(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.Y > endPoint.Y)
            {
                Point newStartPoint = new Point(startPoint.X, startPoint.Y - units);
                Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.Y < endPoint.Y)
            {
                Point newEndPoint = new Point(endPoint.X, endPoint.Y - units);
                Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果水平对齐，则不更改。
        }

        public override void ExpandToBottom(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.Y > endPoint.Y)
            {
                Point newStartPoint = new Point(startPoint.X, startPoint.Y + units);
                Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.Y < endPoint.Y)
            {
                Point newEndPoint = new Point(endPoint.X, endPoint.Y + units);
                Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果水平对齐，则不更改。
        }

        public override void CollapseToLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.X > endPoint.X)
            {
                Point newStartPoint = new Point(startPoint.X - units, startPoint.Y);
                Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.X < endPoint.X)
            {
                Point newEndPoint = new Point(endPoint.X - units, endPoint.Y);
                Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果垂直对齐，则不更改
        }

        public override void ExpandToRight(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.X > endPoint.X)
            {
                Point newStartPoint = new Point(startPoint.X + units, startPoint.Y);
                Action actStartPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.X < endPoint.X)
            {
                Point newEndPoint = new Point(endPoint.X + units, endPoint.Y);
                Action actEndPoint = new Action(masterEditor.Id, this.id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果垂直对齐，则不更改
        }

        void startArrowPath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            startCtrl_MouseLeftButtonDown(sender, e);
        }

        public event EventHandler<MouseButtonEventArgs> ControlHandlerDoubleClicked;

        protected void OnControlHandlerDoubleClicked(object sender, MouseButtonEventArgs e)
        {
            if (ControlHandlerDoubleClicked != null)
            {
                ControlHandlerDoubleClicked(sender, e);
            }
        }

        void startCtrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            this.SelectOnlySelf();

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = startPoint;
            draggingType = ControlDraggingType.Start;
            masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveLineWidgetControler;

            startCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        public override void UpdatePointsWhenPasting(Point basePasteTopLeft)
        {
            Point newStartPoint = new Point(startPoint.X + basePasteTopLeft.X,
                startPoint.Y + basePasteTopLeft.Y);

            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X + basePasteTopLeft.X,
                endPoint.Y + basePasteTopLeft.Y);

            EndPoint = newEndPoint;
        }

        #endregion


        #region 事件=========================================================================================================


        #endregion

    }
}
